﻿using System;
using System.Collections.Generic;
using Cjc.ExpressionEngine.Excel.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting.Hosting.Providers;
using System.Threading;

namespace Cjc.ExpressionEngine
{
	public interface ICellContext
	{
		Cell GetCell( SymbolId symbol );
	}

	public class Worksheet : ICellContext
	{
		internal Engine Engine { get; private set; }
		internal ScriptScope Scope { get; private set; }

		private ObjectOperations operations = null;
		private Dictionary<SymbolId, Cell> cells = new Dictionary<SymbolId, Cell>();

		public Worksheet( Engine engine )
		{
			this.Engine = engine;
			this.Scope = HostingHelpers.CreateScriptScope( engine.ScriptEngine, new ExcelScope( this ) );
		}

		public ObjectOperations Operations
		{
			get
			{
				if ( operations == null )
				{
					Interlocked.CompareExchange<ObjectOperations>(
						ref operations,
						Engine.ScriptEngine.CreateOperations( Scope ),
						null );
				}

				return operations;
			}
		}

		public Cell this[ string key ]
		{
			get { return GetCell( SymbolTable.StringToCaseInsensitiveId( key ) ); }
		}

		internal Cell GetCell( SymbolId symbol )
		{
			lock ( cells )
			{
				return cells.ContainsKey( symbol )
					? cells[ symbol ]
					: cells[ symbol ] = new Cell( Scope, Engine[ symbol ] );
			}
		}

		public object Evaluate( string expression )
		{
			var formula = new Formula( Engine )
			{
				ExpressionText = expression
			};

			return formula.Execute( Scope );
		}

		#region ICellContext Members

		Cell ICellContext.GetCell( SymbolId symbol )
		{
			return GetCell( symbol );
		}

		#endregion
	}
}